using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Admin.NET.Application.EventBus;
using Admin.NET.Application.Service.Sms;
using Admin.NET.Application.Service.Sms.Dto;
using Admin.NET.Core;
using Admin.NET.Core.Service;
using Furion;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.EventBus;
using Furion.FriendlyException;
using Lazy.Captcha.Core;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using NewLife.Caching;
using Newtonsoft.Json;
using SqlSugar;
using TencentCloud.Sms.V20210111.Models;

namespace Admin.NET.Application;

/// <summary>
/// 短信服务
/// </summary>
[ApiDescriptionSettings(new string[] { "业务应用" }, Order = 100)]
public class SmsService : IDynamicApiController, ITransient, IPrivateDependency
{
	private readonly SqlSugarRepository<MessageConfig> _rep;

	private readonly ICache _cache;

	private readonly UserManager _userManager;

	private readonly SysConfigService _sysConfigService;

	private readonly ICaptcha _captcha;

	public SmsService(SqlSugarRepository<MessageConfig> rep, ICache cache, UserManager userManager, SysConfigService sysConfigService, ICaptcha captcha)
	{
		_rep = rep;
		_cache = cache;
		_userManager = userManager;
		_sysConfigService = sysConfigService;
		_captcha = captcha;
	}

	/// <summary>
	/// 保存短信配置
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/sms/save")]
	public async Task SaveSms(SmsConfigInput input)
	{
		MessageConfig config = await _rep.GetFirstAsync((MessageConfig f) => f.TenantId == (long?)_userManager.TenantId);
		if (config != null)
		{
			input.Id = config.Id;
		}
		MessageConfig entity = input.Adapt<MessageConfig>();
		await _rep.InsertOrUpdateAsync(entity);
	}

	/// <summary>
	/// 获取短信配置
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpGet("/sms/detail")]
	public async Task<MessageConfig> SmsDetail()
	{
		long TenantId = long.Parse(App.User.FindFirst("TenantId").Value);
		return await _rep.GetFirstAsync((MessageConfig u) => u.TenantId == (long?)TenantId);
	}

	/// <summary>
	/// 删除配置
	/// </summary>
	/// <returns></returns>
	[HttpPost("/sms/delete")]
	public async Task DeleteSms()
	{
		long TenantId = long.Parse(App.User.FindFirst("TenantId").Value);
		await _rep.DeleteAsync((MessageConfig d) => d.TenantId == (long?)TenantId);
	}

	/// <summary>
	/// 短信模板列表
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpGet("/sms/template/list")]
	public async Task<dynamic> TemplateList()
	{
		return await _rep.Context.Queryable<MessageTemplate>().ToListAsync();
	}

	/// <summary>
	/// 初始化短信模板
	/// </summary>
	/// <returns></returns>
	[HttpPost("/sms/template/init")]
	public async Task InitTemplate()
	{
		List<MessageTemplate> templates = new List<MessageTemplate>();
		List<MessageTemplate> results = _rep.Context.Queryable<MessageTemplate>().ToList();
		if (!results.Any((MessageTemplate a) => a.Type == 0))
		{
			MessageTemplate captcha = new MessageTemplate
			{
				Type = 0,
				Template = "{1}为您的验证码，请于{2}分钟内填写，如非本人操作，请忽略本短信。"
			};
			templates.Add(captcha);
		}
		if (!results.Any((MessageTemplate a) => a.Type == 1))
		{
			MessageTemplate warning = new MessageTemplate
			{
				Type = 1,
				Template = "您的房间：{1}，余额已不足{2}元，请及时缴费"
			};
			templates.Add(warning);
		}
		if (!results.Any((MessageTemplate a) => a.Type == 2))
		{
			MessageTemplate warning = new MessageTemplate
			{
				Type = 2,
				Template = "您有一笔帐单待支付，请于{1}前登录小程序「小程序名称」确认支付，若已支付，请忽略。"
			};
			templates.Add(warning);
		}
		if (templates.Count > 0)
		{
			await _rep.Context.Insertable(templates).ExecuteCommandAsync();
		}
	}

	/// <summary>
	/// 更新短信模板的templateId
	/// </summary>
	/// <param name="id"></param>
	/// <param name="templateId"></param>
	/// <returns></returns>
	[HttpPost("/sms/template/{id}/{templateId}")]
	public async Task SaveTemplateId(long id, string templateId)
	{
		await (from u in _rep.Context.Updateable<MessageTemplate>().SetColumns((MessageTemplate u) => u.TemplateId == templateId)
			where u.Id == id
			select u).ExecuteCommandAsync();
	}

	/// <summary>
	/// 短信流水
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpGet("/sms/record/page")]
	public async Task<dynamic> Page([FromQuery] MessageRecordInput input)
	{
		ISugarQueryable<MessageRecord> query = _rep.Context.Queryable<MessageRecord>().WhereIF(!string.IsNullOrWhiteSpace(input.PhoneNumber), (MessageRecord u) => u.PhoneNumber.Contains(input.PhoneNumber.Trim())).WhereIF(input.Type.HasValue, (MessageRecord u) => (int?)u.Type == input.Type);
		query = query.OrderBuilder(input);
		return await query.ToPagedListAsync(input.Page, input.PageSize);
	}

	/// <summary>
	/// 租户发送找回密码验证码
	/// </summary>
	/// <param name="phoneNumber"></param>
	/// <returns></returns>
	[AllowAnonymous]
	[HttpPost("/sms/sendcaptchawithpasswordapp")]
	public async Task SendCAPTCHAWithPasswordAPP([FromQuery] string phoneNumber, [FromQuery] string codeId, [FromQuery] string code)
	{
		if (string.IsNullOrWhiteSpace(phoneNumber))
		{
			throw Oops.Bah("无效号码");
		}
		if (await _sysConfigService.GetConfigValue<bool>("sys_captcha"))
		{
			if (string.IsNullOrWhiteSpace(code) || string.IsNullOrWhiteSpace(codeId))
			{
				throw Oops.Bah("请先输入图形验证码");
			}
			if (!_captcha.Validate(codeId, code))
			{
				throw Oops.Bah("图形验证码无效或错误");
			}
		}
		var user = await (from w in _rep.Context.Queryable<SysUser>()
			where w.Phone == phoneNumber
			select w into s
			select new { s.TenantId }).FirstAsync();
		if (user == null || !user.TenantId.HasValue)
		{
			throw Oops.Bah("手机号未注册");
		}
		await SendSms(1300000000001L, phoneNumber);
	}

	/// <summary>
	/// 发送找回密码验证码
	/// </summary>
	/// <param name="phoneNumber"></param>
	/// <returns></returns>
	[AllowAnonymous]
	[HttpPost("/sms/sendcaptchawithpassword")]
	public async Task SendCAPTCHAWithPassword([FromQuery] string phoneNumber, [FromQuery] string codeId, [FromQuery] string code)
	{
		if (string.IsNullOrWhiteSpace(phoneNumber))
		{
			throw Oops.Bah("无效号码");
		}
		if (await _sysConfigService.GetConfigValue<bool>("sys_captcha"))
		{
			if (string.IsNullOrWhiteSpace(code) || string.IsNullOrWhiteSpace(codeId))
			{
				throw Oops.Bah("请先输入图形验证码");
			}
			if (!_captcha.Validate(codeId, code))
			{
				throw Oops.Bah("图形验证码无效或错误");
			}
		}
		var user = await (from w in _rep.Context.Queryable<Owner>()
			where w.PhoneNumber == phoneNumber
			select w into s
			select new { s.TenantId }).FirstAsync();
		if (user == null || !user.TenantId.HasValue)
		{
			throw Oops.Bah("手机号未注册");
		}
		await SendSms(1300000000001L, phoneNumber);
	}

	/// <summary>
	/// 发送修改手机号的验证码
	/// </summary>
	/// <param name="phoneNumber"></param>
	/// <returns></returns>
	[HttpPost("/sms/sendcaptchawithchangephone")]
	public async Task SendCAPTCHAWithChangePhone([FromQuery] string phoneNumber, [FromQuery] string codeId, [FromQuery] string code)
	{
		if (string.IsNullOrWhiteSpace(phoneNumber))
		{
			throw Oops.Bah("无效号码");
		}
		if (await _sysConfigService.GetConfigValue<bool>("sys_captcha"))
		{
			if (string.IsNullOrWhiteSpace(code) || string.IsNullOrWhiteSpace(codeId))
			{
				throw Oops.Bah("请先输入图形验证码");
			}
			if (!_captcha.Validate(codeId, code))
			{
				throw Oops.Bah("图形验证码无效或错误");
			}
		}
		await SendSms(_userManager.TenantId, phoneNumber);
	}

	/// <summary>
	/// 发送房间催缴短信(首页)
	/// </summary>
	/// <param name="roomId">房间id</param>
	/// <returns></returns>
	[HttpPost("/sms/sendcallsms")]
	public async Task SendCallSms([FromQuery] long roomId, [FromQuery] string code, [FromQuery] string codeId)
	{
		Room room = await (from w in _rep.Context.Queryable<Room>()
			where w.Id == roomId
			select w).FirstAsync();
		if (room == null)
		{
			throw Oops.Bah("房间不存在");
		}
		if (!room.OwnerId.HasValue)
		{
			throw Oops.Bah("房间未绑定业主");
		}
		Owner owner = await (from w in _rep.Context.Queryable<Owner>()
			where (long?)w.Id == room.OwnerId
			select w).FirstAsync();
		_ = owner.PhoneNumber;
		if (await _sysConfigService.GetConfigValue<bool>("sys_captcha"))
		{
			if (string.IsNullOrWhiteSpace(code) || string.IsNullOrWhiteSpace(codeId))
			{
				throw Oops.Bah("请先输入图形验证码");
			}
			if (!_captcha.Validate(codeId, code))
			{
				throw Oops.Bah("图形验证码无效或错误");
			}
		}
		decimal newbalance = Math.Round(room.Balance, 2);
		BillNoticePayload billNoticePayload = new BillNoticePayload
		{
			Body = $"您的房间：{room.Name}余额不足，剩余{newbalance}元，请及时充值。",
			Subject = "余额不足提醒",
			Remark = "若已充值，请忽略",
			Owners = new List<Owner> { owner },
			RoomId = room.Id,
			RoomName = room.Name,
			Balance = newbalance,
			Path = "/userPage/roompay/roompay?roomId=" + room.Id
		};
		EventPayload payload = new EventPayload
		{
			Data = JsonConvert.SerializeObject(billNoticePayload),
			TenantId = room.TenantId.Value
		};
		for (int i = 0; i < 4; i++)
		{
			MessageCenter.PublishAsync($"{i}:SendEarlyWarningNotice", payload).Wait();
		}
	}

	/// <summary>
	/// 发送短信 
	/// </summary>
	/// <param name="tenantId">当前租户id</param>
	/// <param name="phoneNumber">接收方的手机号</param>
	/// <param name="type">类型，0验证码，1催缴短信</param>
	/// <param name="roomName">房间名称，催缴短信必传</param>
	/// <param name="balanceLimit">预警方案限额，催缴短信必传</param>
	/// <param name="enddate">截止日期</param>
	/// <returns></returns>
	[NonAction]
	public async Task SendSms(long? tenantId, string phoneNumber, int type = 0, string roomName = null, string balanceLimit = null, string[] phoneNumbers = null, string enddate = null)
	{
		MessageConfig smsConfig = await (from w in _rep.Context.Queryable<MessageConfig>()
			where w.TenantId == tenantId
			select w).FirstAsync();
		if (smsConfig == null || (smsConfig.IsBuy == 0 && (string.IsNullOrWhiteSpace(smsConfig.SdkAppId) || string.IsNullOrWhiteSpace(smsConfig.SecretId) || string.IsNullOrWhiteSpace(smsConfig.SecretKey) || string.IsNullOrWhiteSpace(smsConfig.SignName))))
		{
			throw Oops.Bah("未开通短信服务，请到线下办理");
		}
		MessageTemplate template;
		if (smsConfig.IsBuy == 1)
		{
			long buyCount = smsConfig.BuyTotal;
			if (buyCount <= await (from w in _rep.Context.Queryable<MessageRecord>()
				where w.TenantId == tenantId
				select w).CountAsync())
			{
				throw Oops.Bah("当前短信包已用完，请购买套餐包");
			}
			smsConfig = await (from w in _rep.Context.Queryable<MessageConfig>()
				where w.TenantId == (long?)1300000000001L
				select w).FirstAsync();
			if (smsConfig == null)
			{
				throw Oops.Bah("请联系管理员，短信无法发送");
			}
			template = await (from w in _rep.Context.Queryable<MessageTemplate>()
				where w.TenantId == (long?)1300000000001L && w.Type == type
				select w into s
				select new MessageTemplate
				{
					TemplateId = s.TemplateId
				}).FirstAsync();
			if (template == null || string.IsNullOrWhiteSpace(template.TemplateId))
			{
				throw Oops.Bah("未开通短信服务，请到线下办理");
			}
		}
		else
		{
			template = await (from w in _rep.Context.Queryable<MessageTemplate>()
				where w.TenantId == tenantId && w.Type == type
				select w into s
				select new MessageTemplate
				{
					TemplateId = s.TemplateId
				}).FirstAsync();
			if (template == null || string.IsNullOrWhiteSpace(template.TemplateId))
			{
				throw Oops.Bah("未开通短信服务，请到线下办理");
			}
		}
		SendSmsResponse res = null;
		List<string> @params = null;
		if (type == 0)
		{
			(res, @params) = await SmsTool.SendCAPTCHA(_cache, phoneNumber, smsConfig.SignName, template.TemplateId, smsConfig.SecretId, smsConfig.SecretKey, smsConfig.SdkAppId);
		}
		else if (type == 1)
		{
			(res, @params) = await SmsTool.SendBalnceCall(roomName, balanceLimit, phoneNumber, smsConfig.SignName, template.TemplateId, smsConfig.SecretId, smsConfig.SecretKey, smsConfig.SdkAppId);
		}
		else if (type == 2)
		{
			(res, @params) = await SmsTool.SendBillCall(enddate, phoneNumbers, smsConfig.SignName, template.TemplateId, smsConfig.SecretId, smsConfig.SecretKey, smsConfig.SdkAppId);
		}
		if (res == null)
		{
			throw Oops.Bah("短信发送失败");
		}
		MessageRecord record = new MessageRecord
		{
			PhoneNumber = (phoneNumber ?? string.Join(",", phoneNumbers)),
			TenantId = tenantId,
			Type = type,
			Params = @params,
			RequestId = res?.RequestId
		};
		SendSmsResponse sendSmsResponse = res;
		if (sendSmsResponse != null && sendSmsResponse.SendStatusSet.Length != 0)
		{
			SendSmsResponse sendSmsResponse2 = res;
			record.Code = ((sendSmsResponse2 != null) ? sendSmsResponse2.SendStatusSet[0].Code : null);
			SendSmsResponse sendSmsResponse3 = res;
			record.Message = ((sendSmsResponse3 != null) ? sendSmsResponse3.SendStatusSet[0].Message : null);
		}
		_rep.Context.Insertable(record).ExecuteCommand();
	}
}
